package gov.pbc.nn.kjgl.maintenance.view;

import gov.pbc.nn.core.bdf.IUserSelect;
import gov.pbc.nn.core.bdf.entity.Dept;
import gov.pbc.nn.core.bdf.service.UserService;
import gov.pbc.nn.core.bdf.service.UserService.DefaultUserRowMapper;
import gov.pbc.nn.core.dao.CommonHibernateDao;
import gov.pbc.nn.core.dao.CommonJdbcDao;
import gov.pbc.nn.core.dao.PbcnnCoreHibernateDao;
import gov.pbc.nn.core.dao.PbcnnCoreJdbcDao;
import gov.pbc.nn.core.utils.SecurityUtils;
import gov.pbc.nn.kjgl.Constants;
import gov.pbc.nn.kjgl.maintenance.entity.SysEntity;
import gov.pbc.nn.kjgl.maintenance.entity.SysInspectionTask;
import gov.pbc.nn.kjgl.maintenance.entity.SysOperationStaff;
import gov.pbc.nn.uflo.entity.Opinion;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.annotation.Resource;
import javax.persistence.Table;

import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.bstek.bdf2.core.business.IUser;
import com.bstek.bdf2.core.context.ContextHolder;
import com.bstek.bdf2.core.model.RoleMember;
import com.bstek.bdf2.core.orm.ParseResult;
import com.bstek.bdf2.core.orm.hibernate.ISessionCallback;
import com.bstek.bdf2.core.service.IUserService;
import com.bstek.dorado.annotation.DataProvider;
import com.bstek.dorado.annotation.DataResolver;
import com.bstek.dorado.annotation.Expose;
import com.bstek.dorado.data.entity.EntityState;
import com.bstek.dorado.data.entity.EntityUtils;
import com.bstek.dorado.data.provider.Criteria;
import com.bstek.dorado.data.provider.Page;

@Component
public class SysManagePR implements IUserSelect {

	@Resource(name = CommonHibernateDao.BEAN_ID)
	private CommonHibernateDao hibernateDao;
	@Resource(name = CommonJdbcDao.BEAN_ID)
	private CommonJdbcDao jdbcDao;
	@Resource(name = PbcnnCoreHibernateDao.BEAN_ID)
	private PbcnnCoreHibernateDao coreHibernateDao;
	@Resource(name = PbcnnCoreJdbcDao.BEAN_ID)
	private PbcnnCoreJdbcDao coreJdbcDao;

	@DataProvider
	public void loadSys(Page<SysEntity> page, Criteria criteria) {
		
		DetachedCriteria dc = this.hibernateDao.buildDetachedCriteria(criteria, SysEntity.class);
		dc.add(Restrictions.eq("invalid", false));
		dc.add(Restrictions.in("auditState", new Object[] { 1, 2 }));
		Dept dept = (Dept) ContextHolder.getLoginUser().getDepts().get(0);
		Dept zzDept = (Dept) SecurityUtils.getZZByDept(dept);
		if (!Dept.NANNING.equals(zzDept.getId())) {
		dc.add(Restrictions.or(Restrictions.eq("deptId", dept.getId()), Restrictions.eq("operationDeptId", dept.getId())));
		}
		dc.addOrder(Order.asc("auditState"));
		this.hibernateDao.pagingQuery(page, dc);
	}

	/**
	 * 加载运维人员
	 * 
	 * @param sysId
	 * @return
	 */
	@DataProvider
	public List<SysOperationStaff> loadOperationStaff(String sysId) {
		DetachedCriteria dc = DetachedCriteria.forClass(SysOperationStaff.class);
		dc.add(Restrictions.eq("sysId", sysId));
		dc.add(Restrictions.eq("invalid", false));
		return (List<SysOperationStaff>) this.hibernateDao.query(dc);
	}

	@DataProvider
	public void loadInspectionTask(Page<SysInspectionTask> page, Criteria criteria, Map<String, Object> params) {
		String sysId = (String) params.get("sysId");
		DetachedCriteria dc = this.hibernateDao.buildDetachedCriteria(criteria, SysInspectionTask.class);
		dc.add(Restrictions.eq("invalid", false));
		this.hibernateDao.pagingQuery(page, dc);
	}

	@DataProvider
	public List<SysInspectionTask> loadInspectionTask(Map<String, Object> params) {
		String sysId = (String) params.get("sysId");
		Date startDate = (Date) params.get("startDate");
		Date endDate = (Date) params.get("endDate");
		String hql = "from " + SysInspectionTask.class.getName()
				+ " where sysId=:sysId and invalid=false and ((:startDate>=startDate and :startDate<=endDate) or (:endDate>=startDate and :endDate<=endDate) or ( :startDate<startDate and :endDate>endDate) or (:startDate>startDate and :endDate<endDate))";
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("sysId", sysId);
		map.put("startDate", startDate);
		map.put("endDate", endDate);

		List<SysInspectionTask> list = this.hibernateDao.query(hql, map);
		return list;
	}

	@Expose
	@Transactional
	public void deleteInspectionTask(String id) {
		this.hibernateDao.delete(id, SysInspectionTask.class);
	}

	/**
	 * 保存运维人员
	 * 
	 * @param sys
	 */
	@DataResolver
	@Transactional
	public void saveOperationStaff(SysEntity sys) {
		List<SysOperationStaff> staffs = EntityUtils.getValue(sys, "staffs");
		for (SysOperationStaff staff : staffs) {
			EntityState state = EntityUtils.getState(staff);
			if (state == EntityState.NEW) {
				staff.setSysId(sys.getId());
				staff.setSysName(sys.getName());
				this.hibernateDao.save(staff);
				// 赋予运维人员“系统运维”的角色
				this.updateRole(sys.getId(), staff.getUsername(), Constants.ROLE_XTYUNWEI, 0);
			} else if (state == EntityState.MODIFIED) {
				this.hibernateDao.update(staff);
			} else if (state == EntityState.DELETED) {
				this.hibernateDao.delete(staff);
				this.updateRole(staff.getSysId(), staff.getUsername(), Constants.ROLE_XTYUNWEI, 1);
			}
		}
	}

	@Expose
	@Transactional
	public void deleteOperationStaff(String id) {
		SysOperationStaff staff = this.hibernateDao.get(id, SysOperationStaff.class);
		this.hibernateDao.delete(staff);
		this.updateRole(staff.getSysId(), staff.getUsername(), Constants.ROLE_XTYUNWEI, 1);
	}

	private String getRoleId(String roleName) {
		String hql = "select id from Role where name=:roleName";
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("roleName", roleName);
		List<String> ls = coreHibernateDao.query(hql, map);
		return ls.isEmpty() ? null : ls.get(0);
	}

	private RoleMember getRoleMemberByUsername(String username, String roleName) {
		DetachedCriteria dc = DetachedCriteria.forClass(RoleMember.class);
		dc.add(Restrictions.eq("roleId", this.getRoleId(roleName)));
		dc.add(Restrictions.eq("username", username));
		List<RoleMember> rmList = (List<RoleMember>) this.coreHibernateDao.query(dc);
		return (rmList == null || rmList.isEmpty()) ? null : rmList.get(0);
	}

	private void updateRole(String sysId, String username, String roleName, int type) {
		if (type == 0) {
			// insert
			RoleMember rm = this.getRoleMemberByUsername(username, roleName);
			if (rm == null) {
				final RoleMember roleMember = new RoleMember();
				roleMember.setId(UUID.randomUUID().toString());
				roleMember.setRoleId(this.getRoleId(roleName));
				roleMember.setGranted(true);
				roleMember.setCreateDate(new Date());
				roleMember.setUsername(username);
				roleMember.setGranted(true);
				this.coreHibernateDao.doInHibernateSession(new ISessionCallback<Void>() {

					@Override
					public Void doInSession(Session session) {
						session.save(roleMember);
						return null;
					}

				});
				SecurityUtils.refreshComponentSecurityMetadata();
				SecurityUtils.refreshUrlSecurityMetadata();
			}

		} else if (type == 1) {
			// delete
			// 首先判断该用户是否具有其他系统的运维身份
			String hql = "select count(*) from " + SysOperationStaff.class.getName()
					+ " where invalid=false and sysId!=:sysId";
			final Map<String, Object> params = new HashMap<String, Object>();
			params.put("sysId", sysId);
			int count = this.hibernateDao.queryForInt(hql, params);
			if (count == 0) {
				// 没有作为其他系统的运维人员的身份，则删除该角色成员
				final String hql2 = "delete " + RoleMember.class.getName()
						+ " where roleId=:roleId and username=:username";
				params.clear();
				params.put("roleId", this.getRoleId(roleName));
				params.put("username", username);
				this.coreHibernateDao.doInHibernateSession(new ISessionCallback<Void>() {

					@Override
					public Void doInSession(Session session) {
						session.createQuery(hql2).setProperties(params).executeUpdate();
						return null;
					}

				});
				SecurityUtils.refreshComponentSecurityMetadata();
				SecurityUtils.refreshUrlSecurityMetadata();
			}
		}
	}

	@DataResolver
	@Transactional
	public void saveInspectionTask(SysInspectionTask task) {
		EntityState state = EntityUtils.getState(task);
		if (state == EntityState.NEW) {
			this.hibernateDao.save(task);
		} else if (state == EntityState.MODIFIED) {
			this.hibernateDao.update(task);
		}
	}

	@Expose
	@Transactional
	public void auditSys(Map<String, Object> params) {
		final String sysId = (String) params.get("sysId");
		final int agree = Integer.parseInt(params.get("agree").toString());
		String opinion = (String) params.get("opinion");

		this.hibernateDao.doInHibernateSession(new ISessionCallback<Void>() {

			@Override
			public Void doInSession(Session session) {
				SysEntity sys = (SysEntity) session.get(SysEntity.class, sysId);
				sys.setAuditState(agree == 0 ? 3 : 2);
				return null;
			}

		});
		Opinion o = new Opinion();
		o.setBusKey(sysId);
		o.setBusTable(SysEntity.class.getAnnotation(Table.class).name());
		o.setCname(ContextHolder.getLoginUser().getCname());
		o.setDeptId(ContextHolder.getLoginUser().getDepts().get(0).getId());
		o.setDeptName(ContextHolder.getLoginUser().getDepts().get(0).getName());
		o.setUsername(ContextHolder.getLoginUserName());
		o.setOpinion(opinion);
		this.coreHibernateDao.save(o);

	}

	/**
	 * 根据运维部门ID加载其下的人员，用于设置系统的运维人员
	 */
	@Override
	public void loadUsers(Page<IUser> page, Criteria criteria, Map<String, Object> params) throws Exception {
		// 运维部门ID
		String operationDeptId = (String) params.get("operationDeptId");

		this.loadUsersByDeptIdForPage(page, operationDeptId, criteria);

	}

	private void loadUsersByDeptIdForPage(Page<IUser> page, String deptId, Criteria criteria) {
		String sql = "SELECT\n" + "	DISTINCT *\n" + "FROM\n" + "	(\n" + "		SELECT\n"
				+ "			U.*, D.ID_ AS DEPT_ID_,\n" + "			D.NAME_ AS DEPT_NAME_\n" + "		FROM\n"
				+ "			t_user U\n" + "		INNER JOIN bdf2_user_dept UD ON U.USERNAME_ = UD.USERNAME_\n"
				+ "		INNER JOIN t_dept D ON UD.DEPT_ID_ = D.ID_  order by D.ID_,U.USERNAME_\n" + "	) T\n"
				+ "WHERE\n" + "	T.DEPT_ID_ like :deptId";
		ParseResult result = jdbcDao.parseCriteria(criteria, true, "T");
		if (result != null) {
			StringBuffer sb = result.getAssemblySql();
			Map<String, Object> valueMap = result.getValueMap();
			sql += " AND " + sb.toString();
			valueMap.put("deptId", deptId + "%");
			coreJdbcDao.pagingQuery(page, sql, new DefaultUserRowMapper(), valueMap);
		} else {
			Map<String, Object> params = new HashMap<String, Object>();
			params.put("deptId", deptId + "%");
			coreJdbcDao.pagingQuery(page, sql, new DefaultUserRowMapper(), params);
		}
	}
}
